<?php
namespace Admin\Model;
use Think\Model;
//$fp = null;
class OrderModel extends Model{
    // 下单时允许表单的字段
    protected $insertFields = array('shr_name','shr_tel','shr_province','shr_city','shr_area','shr_address');
    // 下单时的表单验证规则
    protected $_validate = array(
        array('shr_name', 'require', '收货人姓名不能为空！', 1, 'regex', 3),
        array('shr_tel', 'require', '收货人电话不能为空！', 1, 'regex', 3),
        array('shr_province', 'require', '所在省不能为空！', 1, 'regex', 3),
        array('shr_city', 'require', '所在城市不能为空！', 1, 'regex', 3),
        array('shr_area', 'require', '所在地区不能为空！', 1, 'regex', 3),
        array('shr_address', 'require', '详细地址不能为空！', 1, 'regex', 3),
    );
    public function _before_insert(&$data,&$option)
    {
        $memberId = session('m_id');
        /************下单前检查************/
        //检查是否登录
        if(!$memberId){
            $this->error ="请先登录！";
            exit;
        }
        //检查购物车是否有商品
        $cartModel = D('cart');

//       $this->goods = $goods = $cartModel->cartLst();//获取购物车的商品 如果没有也不行
        $option['goods'] = $goods = $cartModel->cartLst();//获取购物车的商品 如果没有也不行
        if(!$goods){
            $this->error ="您还没有选购商品！";
            exit;
        }

        /**************z在检查库存量前就要枷锁 ***********************/
        // 这里不能是局部变量 不然等到检查完之后就会释放掉
        //所以呢 这个锁在模型里 最好 直接赋给模型 只有这个模型的所有脚本走完 才会释放 如下
        /**************或者就放到模型最上面定义一个一样的变量 值为null ************/
        $this->fp = fopen('./order.lock');
        flock($this->fp,LOCK_EX);           //排他锁


        // 如果购物车有商品循环购物车的商品检查库存量 并且计算购买商品的总价 给下面用
        $gnModel = D('goods_number');
        $total_price = 0;//商品总价
        foreach($goods as $k=>$v){
            $gnNumber = $gnModel->field('goods_number')->where(array(
                'goods_id'=>array('eq',$v['goods_id']),
                'goods_attr_id'=>array('eq',$v['goods_attr_id']),
            ))->find();
            if($gnNumber['goods_number']<$v['goods_number']){
                $this->error ='下单失败，原因：<strong>'.$v['goods_name'].'</strong>库存不足';
                return FALSE;  //这里就不能停止了 就返回控制器去
            }
            $total_price += $v['goods_price']*$v['goods_number'];           //循环商品的数量乘以商品价格 就是总价
        }

        /*********************开启事务*************************/
        //为了确保三张表操作都能成功： 订单基本信息表 订单商品信息表 库存量表
        //从只要开始使用表 添加 插入之前使用

        $this->startTrans();                    //开启事务


        //把其他信息补到订单表中
        $data['member_id'] = $memberId;
        $data['addtime'] = time();
        $data['total_price'] = $total_price;
    }

/**********************订单基本信息添加到订单表中后 得到订单表的id 再找到购物车的商品信息 把购物车的信息再添加到商品订单表中 这俩表是分开的******************************/
    public function _after_insert($data,$option)
    {
//        $cartModel = D('cart');
//        $goods = $cartModel->cartLst();//获取购物车的商品 如果没有也不行
//        session('goods',$goods); 存session 也可以
//        可不可以不调了 因为这个方法里连了好几张表 多次使用会拖慢速度  现在解决办法是一个可以实例化后存session
        //最好的办法是赋给模型 自定义一个模型变量$this->goods 这里就直接可以用$this->goods了
        /*******还有一种方法 就是放到option中 但是这个option 必须也是和data一样要按引用传参  添加前的optin可以直接传到添加后的这个option里******/
        /**********************所以这里可以循环option 得到信息 插入商品订单表*****************/
        $ogModel = D('order_goods');
        $gnMolde = D('goods_number');
        foreach($option['goods'] as $k=>$v){
           $ret =  $ogModel->add(array(
                'order_id'=>$data['id'],
                'goods_id'=>$v['goods_id'],
                'goods_name'=>$v['goods_name'],
                'goods_attr_id'=>$v['goods_attr_id'],
                'goods_price'=>$v['goods_price'],
                'goods_number'=>$v['goods_number'],

            ));
            /****************如果失败就回滚事务*******************/
            if(!$ret){
                $this->rollback();
                return FALSE;
            }

            //这里下单结束后 减去商品的库存量
            $ret = $gnMolde->where(array(
                'goods_id'=>array('eq',$v['goods_id']),                    //到这个表里面 查找对应的商品减去购物车里这个商品的数量
                'goods_attr_id'=>array('eq',$v['goods_attr_id']),
            ))->setDEC('goods_number',$v['goods_number']); //setDEC 减去当前字段数量多少

            /****************如果失败就回滚事务*******************/
            //修改的时候要这一判断事务回滚
            if(FALSE === $ret){
                $this->rollback();
                return FALSE;
            }
        }
        //到此 下单结束 会员订单信息 和商品信息都各自存到了对应的表里了  最后下单后 商品的库存一定要减掉



        /**********************提交事务***********************/
        //所有操作都成功后
        $this->comment();


        //这里释放锁 PHP锁可以不用手动释放 php有垃圾回收机制 当脚本走完 会自动释放 但是为了不堵塞严重 这里早一点释放锁
        flock($this->fp,LOCK_UN);
        fclose($this->fp);              //最后关闭这个文件 让下一个抢锁


        /***********最后下单成功要把这个购物车清空***************/
        $cartModel = D('Home/cart');
//        $cartModel->clear();                    //这个方法在前台的cart模型里
    /********************以上这一写会在高并发的时候回出错  所以要加个文件锁 PHP的***********************/
    }


    /********************************取出所有订单 展示在前台的我的订单页中*******************************************/
    public function search($pageSize = 5)
    {
        /**************************************** 搜索 ****************************************/
        $memberId = session('m_id');
        $where['member_id'] = array('eq', $memberId);
        $noPayCount = $this->where(array(
            'member_id' => array('eq', $memberId),
            'pay_status' => array('eq', '否'),
        ))->count();
        /************************************* 翻页 ****************************************/
        $count = $this->alias('a')->where($where)->count();
        $page = new \Think\Page($count, $pageSize);
        // 配置翻页的样式
        $page->setConfig('prev', '上一页');
        $page->setConfig('next', '下一页');
        $data['page'] = $page->show();
        /************************************** 取数据 ******************************************/
        $data['data'] = $this->alias('a')
            ->field('a.id,a.shr_name,a.total_price,a.addtime,a.pay_status,GROUP_CONCAT(DISTINCT c.sm_logo) logo')
            ->join('LEFT JOIN __ORDER_GOODS__ b ON a.id=b.order_id
		        LEFT JOIN __GOODS__ c ON b.goods_id=c.id')
            ->where($where)
            ->group('a.id')
            ->limit($page->firstRow.','.$page->listRows)
            ->select();
        $data['noPayCount'] = $noPayCount;
        return $data;
    }
}